home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / AVIOutputStriped.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  10.1 KB  |  369 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <string.h>
  19.  
  20. #include "Error.h"
  21.  
  22. #include "AVIOutputStriped.h"
  23. #include "AVIStripeSystem.h"
  24.  
  25. ///////////////////////////////////////////////////////////////////////////
  26. //
  27. //    output streams
  28. //
  29. ///////////////////////////////////////////////////////////////////////////
  30.  
  31. class AVIStripedAudioOutputStream : public AVIAudioOutputStream {
  32. public:
  33.     AVIStripedAudioOutputStream(AVIOutput *);
  34.  
  35.     BOOL write(LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer, LONG lSamples);
  36. };
  37.  
  38. AVIStripedAudioOutputStream::AVIStripedAudioOutputStream(AVIOutput *out) : AVIAudioOutputStream(out) {
  39. }
  40.  
  41. BOOL AVIStripedAudioOutputStream::write(LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer, LONG lSamples) {
  42.     ((AVIOutputStriped *)output)->writeChunk(TRUE, dwIndexFlags, lpBuffer, cbBuffer, lTotalSamplesWritten, lSamples);
  43.  
  44.     lTotalSamplesWritten += lSamples;
  45.  
  46.     return TRUE;
  47. }
  48.  
  49. ////////////////////////////////////
  50.  
  51. class AVIStripedVideoOutputStream : public AVIVideoOutputStream {
  52. public:
  53.     AVIStripedVideoOutputStream(AVIOutput *);
  54.  
  55.     BOOL write(LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer, LONG lSamples);
  56. };
  57.  
  58. AVIStripedVideoOutputStream::AVIStripedVideoOutputStream(AVIOutput *out) : AVIVideoOutputStream(out) {
  59. }
  60.  
  61. BOOL AVIStripedVideoOutputStream::write(LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer, LONG lSamples) {
  62.     ((AVIOutputStriped *)output)->writeChunk(FALSE, dwIndexFlags, lpBuffer, cbBuffer, lTotalSamplesWritten, lSamples);
  63.  
  64.     lTotalSamplesWritten += lSamples;
  65.  
  66.     return TRUE;
  67. }
  68.  
  69.  
  70.  
  71. ///////////////////////////////////////////////////////////////////////////
  72. //
  73. //    AVIOutputStriped
  74. //
  75. ///////////////////////////////////////////////////////////////////////////
  76.  
  77. class AVIOutputStripeState {
  78. public:
  79.     __int64        size;
  80.     long        audio_sample, video_sample;
  81. };
  82.  
  83.  
  84.  
  85. AVIOutputStriped::AVIOutputStriped(AVIStripeSystem *stripesys) {
  86.     this->stripesys        = stripesys;
  87.  
  88.     stripe_files        = NULL;
  89.     stripe_data            = NULL;
  90.  
  91.     audio_index_cache_point        = 0;
  92.     video_index_cache_point        = 0;
  93.  
  94.     f1GbMode = false;
  95. }
  96.  
  97. AVIOutputStriped::~AVIOutputStriped() {
  98.     int i;
  99.  
  100.     if (stripe_files) {
  101.         for(i=0; i<stripe_count; i++)
  102.             delete stripe_files[i];
  103.  
  104.         delete[] stripe_files;
  105.     }
  106.     delete[] stripe_data;
  107. }
  108.  
  109. //////////////////////////////////
  110.  
  111. BOOL AVIOutputStriped::initOutputStreams() {
  112.     if (!(audioOut = new AVIStripedAudioOutputStream(this))) return FALSE;
  113.     if (!(videoOut = new AVIStripedVideoOutputStream(this))) return FALSE;
  114.  
  115.     return TRUE;
  116. }
  117.  
  118. void AVIOutputStriped::set_1Gb_limit() {
  119.     f1GbMode = true;
  120. }
  121.  
  122. BOOL AVIOutputStriped::init(const char *szFile, LONG xSize, LONG ySize, BOOL hasVideo, BOOL hasAudio, LONG bufferSize, BOOL is_interleaved) {
  123.     int i;
  124.  
  125.     if (hasAudio) {
  126.         if (!audioOut) return FALSE;
  127.     } else {
  128.         delete audioOut;
  129.         audioOut = NULL;
  130.     }
  131.  
  132.     if (hasVideo) {
  133.         if (!videoOut) return FALSE;
  134.     } else {
  135.         delete videoOut;
  136.         videoOut = NULL;
  137.     }
  138.  
  139.     stripe_count = stripesys->getStripeCount();
  140.  
  141.     if (!(stripe_data = new AVIOutputStripeState [stripe_count]))
  142.         throw MyMemoryError();
  143.  
  144.     memset(stripe_data, 0, sizeof(AVIOutputStripeState)*stripe_count);
  145.  
  146.     if (!(stripe_files = new AVIOutputFile *[stripe_count]))
  147.         throw MyMemoryError();
  148.  
  149.     bool fFoundIndex = false;
  150.  
  151.     for(i=0; i<stripe_count; i++) {
  152.         stripe_files[i] = NULL;
  153.         if (stripesys->getStripeInfo(i)->isIndex())
  154.             fFoundIndex = true;
  155.     }
  156.  
  157.     if (!fFoundIndex)
  158.         throw MyError("Cannot create output: stripe system has no index stripe");
  159.  
  160.     for(i=0; i<stripe_count; i++) {
  161.         AVIStripe *sinfo = stripesys->getStripeInfo(i);
  162.  
  163.         stripe_files[i] = new AVIOutputFile();
  164.  
  165.         if (f1GbMode)
  166.             stripe_files[i]->set_1Gb_limit();
  167.  
  168.         if (!stripe_files[i]->initOutputStreams())
  169.             throw MyMemoryError();
  170.  
  171.         if (hasVideo && (sinfo->isVideo() || sinfo->isIndex())) {
  172.  
  173.             if (sinfo->isIndex()) {
  174.                 BITMAPINFOHEADER *bmih;
  175.  
  176.                 if (!(bmih = (BITMAPINFOHEADER *)stripe_files[i]->videoOut->allocFormat(sizeof(BITMAPINFOHEADER))))
  177.                     throw MyMemoryError();
  178.  
  179.                 memcpy(bmih, videoOut->getFormat(), sizeof(BITMAPINFOHEADER));
  180.  
  181.                 bmih->biSize            = sizeof(BITMAPINFOHEADER);
  182.                 bmih->biCompression        = 'TSDV';
  183.             } else {
  184.                 if (!stripe_files[i]->videoOut->allocFormat(videoOut->getFormatLen()))
  185.                     throw MyMemoryError();
  186.  
  187.                 memcpy(stripe_files[i]->videoOut->getFormat(), videoOut->getFormat(), videoOut->getFormatLen());
  188.             }
  189.  
  190.             memcpy(&stripe_files[i]->videoOut->streamInfo, &videoOut->streamInfo, sizeof(AVIStreamHeader_fixed));
  191.  
  192.             if (sinfo->isIndex()) {
  193.                 stripe_files[i]->videoOut->streamInfo.fccHandler = 'TSDV';
  194.                 stripe_files[i]->videoOut->streamInfo.dwSampleSize    = 16;
  195.  
  196.                 index_file = stripe_files[i];
  197.             }
  198.         }
  199.         if (hasAudio && (sinfo->isAudio() || sinfo->isIndex())) {
  200.             if (!stripe_files[i]->audioOut->allocFormat(audioOut->getFormatLen()))
  201.                 throw MyMemoryError();
  202.  
  203.             memcpy(stripe_files[i]->audioOut->getFormat(), audioOut->getFormat(), audioOut->getFormatLen());
  204.  
  205.             memcpy(&stripe_files[i]->audioOut->streamInfo, &audioOut->streamInfo, sizeof(AVIStreamHeader_fixed));
  206.  
  207.             if (!sinfo->isAudio()) {
  208.                 stripe_files[i]->audioOut->streamInfo.fccType        = 'idua';
  209.                 stripe_files[i]->audioOut->streamInfo.fccHandler    = 'TSDV';
  210.                 stripe_files[i]->audioOut->streamInfo.dwSampleSize    = 16;
  211.  
  212.                 index_file = stripe_files[i];
  213.             }
  214.         }
  215.  
  216.         stripe_files[i]->disable_os_caching();
  217.  
  218.         if (!stripe_files[i]->init(
  219.                     sinfo->szName,
  220.                     xSize,
  221.                     ySize,
  222.                     TRUE,
  223.                     sinfo->isAudio() || sinfo->isIndex(),
  224.                     sinfo->lBufferSize,
  225.                     TRUE))
  226.             throw MyError("Error initializing stripe #%d", i+1);
  227.  
  228.         stripe_files[i]->videoOut->setCompressed(videoOut->isCompressed());
  229.     }
  230.  
  231.     return TRUE;
  232. }
  233.  
  234. BOOL AVIOutputStriped::finalize() {
  235.     int i;
  236.  
  237.     FlushCache(FALSE);
  238.     FlushCache(TRUE);
  239.  
  240.     for(i=0; i<stripe_count; i++)
  241.         if (!stripe_files[i]->finalize())
  242.             return FALSE;
  243.  
  244.     return TRUE;
  245. }
  246.  
  247. BOOL AVIOutputStriped::isPreview() { return FALSE; }
  248.  
  249. void AVIOutputStriped::writeChunk(BOOL is_audio, LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer,
  250.                                         LONG lSampleFirst, LONG lSampleCount) {
  251.     AVIStripeIndexEntry *asie;
  252.     int s, best_stripe=-1;
  253.     long lBufferSize;
  254.     BOOL best_will_block = TRUE;
  255.  
  256.     // Pick a stripe to send the data to.
  257.     //
  258.     // Prioritize stripes that can hold the data without blocking,
  259.     // then on total data fed to that stripe at that point.
  260.  
  261.     for(s=0; s<stripe_count; s++) {
  262.  
  263.         if (is_audio) {
  264.             if (!stripesys->getStripeInfo(s)->isAudio())
  265.                 continue;
  266.         } else {
  267.             if (!stripesys->getStripeInfo(s)->isVideo())
  268.                 continue;
  269.         }
  270.  
  271.         if (stripe_files[s]->bufferStatus(&lBufferSize) >= ((cbBuffer+11)&-4)) {
  272.             // can accept without blocking
  273.  
  274.             if (best_will_block) { // automatic win
  275.                 best_will_block = FALSE;
  276.                 best_stripe = s;
  277.                 continue;
  278.             }
  279.         } else {
  280.             // will block
  281.  
  282.             if (!best_will_block)    // automatic loss
  283.                 continue;
  284.         }
  285.  
  286.         // compare total data sizes
  287.  
  288.         if (best_stripe<0 || stripe_data[best_stripe].size > stripe_data[s].size)
  289.             best_stripe = s;
  290.     }
  291.  
  292.     // Write data to stripe.
  293.  
  294.     if (best_stripe >= 0) {
  295.         if (is_audio)
  296.             stripe_files[best_stripe]->audioOut->write(dwIndexFlags, lpBuffer, cbBuffer, lSampleCount);
  297.         else
  298.             stripe_files[best_stripe]->videoOut->write(dwIndexFlags, lpBuffer, cbBuffer, lSampleCount);
  299.  
  300.         stripe_data[best_stripe].size += cbBuffer+8;
  301.     }
  302.  
  303.     // Write lookup chunk to index stream.
  304.     //
  305.     // NOTE: Do not write index marks to the same stream the data
  306.     //       was written to!
  307.  
  308.     if (index_file != stripe_files[best_stripe]) {
  309.         if (is_audio) {
  310.             if (audio_index_cache_point >= CACHE_SIZE)
  311.                 FlushCache(TRUE);
  312.  
  313.             asie = &audio_index_cache[audio_index_cache_point++];
  314.         } else {
  315.             if (video_index_cache_point >= CACHE_SIZE)
  316.                 FlushCache(FALSE);
  317.  
  318.             asie = &video_index_cache[video_index_cache_point++];
  319.         }
  320.  
  321.         asie->lSampleFirst    = lSampleFirst;
  322.         asie->lSampleCount    = lSampleCount;
  323.         asie->lStripe        = best_stripe;
  324.         asie->lStripeSample    = 0;
  325.  
  326.         if (is_audio) {
  327.             if (best_stripe >= 0) {
  328.                 asie->lStripeSample = stripe_data[best_stripe].audio_sample;
  329.  
  330.                 stripe_data[best_stripe].audio_sample += lSampleCount;
  331.             }
  332.             audio_index_flags[audio_index_cache_point-1] = dwIndexFlags;
  333.             audio_index_count[audio_index_cache_point-1] = lSampleCount;
  334.  
  335. //            index_file->audioOut->write(dwIndexFlags, dwIndexData, sizeof dwIndexData, lSampleCount);
  336.         } else {
  337.             if (best_stripe >= 0) {
  338.                 asie->lStripeSample = stripe_data[best_stripe].video_sample;
  339.  
  340.                 stripe_data[best_stripe].video_sample += lSampleCount;
  341.             }
  342.             video_index_flags[video_index_cache_point-1] = dwIndexFlags;
  343.             video_index_count[video_index_cache_point-1] = lSampleCount;
  344.  
  345. //            index_file->videoOut->write(dwIndexFlags, dwIndexData, sizeof dwIndexData, lSampleCount);
  346.         }
  347.     }
  348. }
  349.  
  350. void AVIOutputStriped::writeIndexedChunk(FOURCC ckid, LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer) {
  351.     index_file->writeIndexedChunk(ckid, dwIndexFlags, lpBuffer, cbBuffer);
  352. }
  353.  
  354. void AVIOutputStriped::FlushCache(BOOL fAudio) {
  355.     int i;
  356.  
  357.     if (fAudio) {
  358.         for(i=0; i<audio_index_cache_point; i++)
  359.             index_file->audioOut->write(audio_index_flags[i], &audio_index_cache[i], sizeof AVIStripeIndexEntry, audio_index_count[i]);
  360.  
  361.         audio_index_cache_point = 0;
  362.     } else {
  363.         for(i=0; i<video_index_cache_point; i++)
  364.             index_file->videoOut->write(video_index_flags[i], &video_index_cache[i], sizeof AVIStripeIndexEntry, video_index_count[i]);
  365.  
  366.         video_index_cache_point = 0;
  367.     }
  368. }
  369.